import json

from re_common.baselibrary.utils.core.mdeprecated import try_except2_async, try_except2

from apps.crawler_platform.core_callback import *
from apps.crawler_platform.core_callback.err_callback import all_client_back_callback
from apps.crawler_platform.core_platform.base_etl import BaseETL
from apps.crawler_platform.core_platform.core_etl import CoreLocalEtlControllerMixin
from apps.crawler_platform.core_platform.core_g import SQLTable
from apps.crawler_platform.core_platform.core_sql import CoreSqlMixin
from apps.crawler_platform.core_platform.g_model import DownModel, HtmlModel, T2, T1, EtlDealModel, \
    JournalEtlArticleModel, EtlCallBackModel
from apps.crawler_platform.qk_platform.base_qk_step import BaseQKItems

# 不执行逻辑，目的是为了不让 from apps.crawler_platform.core_callback import *
# 被编辑器认为没有使用，快捷清除时就不会被清除
from apps.crawler_platform.util.nosqlhelper import NOSQLHelper
from apps.sql_app.mmongodb import Coll

STATICA_HACK = False
# globals()['kcah_acitats'[::-1].upper()] = False
if STATICA_HACK:  # pragma: no cover
    null()


class EtlItems(BaseQKItems):

    def __init__(self):
        super(EtlItems, self).__init__()
        self.task_setting = None
        self.rawid: str = ''
        self.field: dict = {}
        self.down_model_x = None
        self.deal_model: EtlDealModel = EtlDealModel()

    def get_pkm(self):
        """
        获取主键
        :return:
        """
        return {"task_name": self.task_name,
                "task_tag": self.task_tag,
                "rawid": self.rawid
                }

    def set_downmodel(self):
        if self.task_name == "cnkijournal" and self.task_tag == "cnkiarticle":
            self.down_model = DownModel[T2](down_dict={})
            self.down_model_x = T2
        elif self.task_name == "wanfangjournal" and self.task_tag == "wanfangarticle":
            # self.down_model = DownModel[PageHtmlModel[HtmlModel]](down_dict={})
            # self.down_model_x = PageHtmlModel[HtmlModel]
            self.down_model = DownModel[T1](down_dict={})
            self.down_model_x = T1
        else:
            self.down_model = DownModel[HtmlModel](down_dict={})
            self.down_model_x = HtmlModel


class JournalEtlLocal(BaseETL, CoreLocalEtlControllerMixin):

    def __init__(self, request, inputs):
        super().__init__()
        self.err_tag = "qketl_local"
        self.pm = EtlItems()
        self.pm.set_downmodel()

        self.input = inputs
        self.pm.task_name = inputs.data.task_name
        self.pm.task_tag = inputs.data.task_tag
        self.pm.rawid = inputs.data.rawid
        self.pm.field = {"last_data": 1}
        self.pm.Id = inputs.data.rawid

        self.pm.redis = request.app.state.redis

        self.request = request
        self.step_info = ""
        # 解析字段字典
        self.para_dicts = {}

        self.sql_model: JournalEtlArticleModel

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def get_sql(self):
        self.pm.task_setting = self.redis_model.dict()["parse_dict"]["1_1"]["task_set"]
        row = await CoreSqlMixin.get_qk_etl_local_article(
            self.pm.task_setting["table_name"],
            self.pm.task_setting["table_index"],
            self.pm.task_name,
            self.pm.task_tag,
            self.pm.rawid)
        if row and row.get(self.pm.task_setting["final_stat"],"") in [1, 7, 8, 9]:
            self.pm.sql_model = JournalEtlArticleModel.parse_obj(row)
            return True, row
        else:
            if not row:
                return False, {
                    "err_msg": "qk article local etl sql查询不存在;" + ",".join([self.pm.task_tag, self.pm.rawid])}
            else:
                return False, {"code": row["is_true"],
                               "err_msg": "该记录不在解析状态里"}

    @try_except2()
    def verify_para(self):
        """
        验证解析出来的数据
        """
        return True, {}

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def save_sql(self, code, err_msg=""):
        """
        与关系型sql的处理 包括存储下一级的sql以及本级sql的状态和字段更新
        """
        table_name = self.pm.task_setting["table_name"]
        table_index = self.pm.task_setting["table_index"]
        stname = self.pm.task_setting["final_stat"]
        err_msg = str(err_msg)
        await CoreSqlMixin.update_etl_local_article(table_name, table_index, stname, self.pm.task_name,
                                                         self.pm.task_tag, self.pm.rawid, code,
                                                         err_msg)
        return True, ""

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def run_task(self):
        bools, err_info = await self.task_step()
        return bools, err_info

    @try_except2()
    def verify_html(self):
        """
        验证html
        """
        return True, ""

    async def my_task(self, table=""):
        """
        接入调用的task
        ZCN:函数内部有逻辑,因此返回的上层的布尔值
        :return:
        """
        bools, err_info = await super().my_task(SQLTable.journal_article)
        return bools, err_info

    def deal_html(self, *args, **kwargs):
        """
        处理html
        :return:
        """
        super().deal_html(*args, **kwargs)

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def deal_html_etl(self):
        TModel, DModel = JournalEtlArticleModel, self.pm.down_model_x
        self.step_info = self.add_all_process_info(f"处理解析，通过配置css和xpath进行解析")
        bools, err_info = await self.para_next()
        if not bools:
            return bools, err_info
        if "status" in self.para_dicts.keys() and self.para_dicts["status"] == "FAILED":
            return False, {"err_msg": json.dumps(self.para_dicts, ensure_ascii=False)}
        from app_main import app
        self.para_dicts["journal_rawids"] = await app.state.redis.hgetall("journal_rawids")
        callmodel = EtlCallBackModel[TModel, DModel](
            down_model=self.pm.down_model,
            para_dicts=self.para_dicts,
            sql_model=self.pm.sql_model,
            redis_all=self.redis_model
        )
        # self.pm.deal_model is EtlDealModel
        self.pm.deal_model = self.callback_deal_html_etl(callmodel)
        if self.pm.deal_model.status == "FAILED":
            return False, {"err_msg": self.pm.deal_model.err_msg}
        ref_state = self.pm.down_model.ref_state
        if len(ref_state) > 0 :
            mongo_conn = Coll.get_table_conn(ref_state["table"])  # 根据table名取得mongo链接
            cjip = await NOSQLHelper.find_one(mongo_conn, {"_id": ref_state["lngid"]})
            if cjip:
                cjip["is_deprecated"] = "1"
                ref_depr = {"table": ref_state["table"], "data": cjip}
                #self.pm.down_model.save_data.append(ref_depr)
                ref_depr_conn = Coll.get_table_conn("ref_deprecated")
                await NOSQLHelper.insert_one(ref_depr_conn,ref_depr)
        return True, {}

    def callback_deal_html_etl(self, callmodel) -> EtlDealModel:
        name = "_".join([self.pm.task_name, self.pm.task_tag, "etl", "callback"])
        callback = eval(name)
        return callback(callmodel)
